/* kernel.h - disable, enable, halt, restore, isodd, min, max */

/* Symbolic constants used throughout Xinu */

typedef	char		Bool;		/* Boolean type			*/
typedef unsigned int    uint;

#define	FALSE		0		/* Boolean constants		*/
#define	TRUE		1
#define	EMPTY		(-1)		/* an illegal gpq		*/
#define	NULL		0		/* Null pointer for linked lists*/
#define	NULLCH		'\0'		/* The null character		*/


/* Universal return constants */

#define	OK		 1		/* system call ok		*/
#define	SYSERR		-1		/* system call failed		*/
#define	EOF		-2		/* End-of-file (usu. from read)	*/
#define	TIMEOUT		-3		/* time out  (usu. recvtim)	*/
#define	INTRMSG		-4		/* keyboard "intr" key pressed	*/
					/*  (usu. defined as ^B)	*/
#define	BLOCKERR	-5		/* non-blocking op would block	*/

/* Student-defined stuff*/
#define INT_CSWITCH 63 			/* System call interrupt */
#define INT_TIMER 0x20

#define NUM_PCB 64			/* Number of statically allocated PCB's (see disp.c) */

#define STDSTACKSIZ 4096		/* Standard initial stack size for new process' */
	
#define PID_COUNT_START 100		/* First PID that will be given out */

#define CPPADDING 16 			/* Number of bytes to pad a new process' stack by */

#define REQ_CREATE 0			/* System call create */
#define REQ_YIELD 1			/* System call yield */
#define REQ_STOP 2			/* System call stop */
#define REQ_GETPID 4			/* System call getpid */
#define REQ_PUTS 8			/* System call puts */
#define REQ_TIMER 16			/* Timer interrupt request */
#define REQ_SEND 32			/* System call send */
#define REQ_RECV 64			/* System call receive */
#define REQ_SLEEP 128			/* System call sleep */


#define PROC_RUNNING 0x0		/* Process state running */
#define PROC_BLOCKED 0x1		/* Process state blocked */
#define PROC_READY 0x2			/* Process state ready */
#define PROC_DEAD 0x4			/* Process state dead */
#define PROC_BLOCKEDONRECV 8		/* Process state blocked waiting for sender */
#define PROC_BLOCKEDONSEND 16		/* Process state blocked waiting for receiver */

#define RECV_ANY 0			/* Global constant for Receive Any syscall */

#define CLOCK_TICK 10			/* Length of a clock tick (time slice) in MS*/
#define CLOCK_DIVISOR 100		/* Clock ticks every 10ms */

typedef struct CPU_context{		/* CPU_context is a struct used to position and */
	unsigned int edi;		/* 	and reference process/kernel context while */
	unsigned int esi;		/* 	on the stack*/
	unsigned int ebp;
	unsigned int esp;
	unsigned int ebx;
	unsigned int edx;
	unsigned int ecx;
	unsigned int eax;
	unsigned int iret_eip;
	unsigned int iret_cs;
	unsigned int eflags;
}CPU_context;


typedef struct PCB{			/* PCB struct used to store process information for */
	unsigned int pid;		/* 	the kernel 		PID = process id   */
	int state;			/* State is currently unused 			*/
	int parent_pid;			/* Parent_pid is currently unused		*/
	CPU_context* cpu_state;		/* cpu_state is initialized but not later referenced */
					/* 	(see create.c) 				*/
	struct PCB* next;		/* next is used to implement ready, dead and blocked */
					/*	queues					*/
	void* stack;			/* stack saves a process' stack pointer/esp on context */
					/*	switch					*/
	void* initial_stack;		/* used to free the stack's initial stack. TODO basic
						but works for current implementation 	*/
	int rc;				/* return value 		*/
	struct PCB* blocked_senders_q; 
}PCB;

typedef struct Syscall_args{		/* statically defined structure for passing syscall */
	int arg0;		/* args into kernel with a single pointer 	    */
	int arg1;
	int arg2;
	int arg3;	
}Syscall_args;

PCB* idle_proc_ptr;

/* mem.c */
extern void kmeminit(void);		//Initialize memory management		
extern void* kmalloc(int size);		//Allocated physical memory
extern void kfree(void* ptr);		//Free physical memory

/* disp.c */
extern void proccontrolinit(void); 	//Initialize process control structures
extern void dispatch(void);		//Start dispatcher
extern PCB* rq_next(void);		//Get a free PCB to use (ie. for create())
extern void ready(PCB* p);		//Add PCB* p to ready queue
extern PCB* get_pcb(void);

/* ctsw.c */
extern int contextswitch(PCB* curr_proc);	//Context switch into process curr_proc
extern void contextinit(void);			//Initialize context switcher interrupt

/* create.c */
extern void pidcounterinit(void);		//Initialize pid counter
extern int create( void (*fn)(), int stack);	//Create process with entry point fn and stack size stack
extern int __create( void (*fn)(), int stack, PCB* proc_pcb, int b_ready); // Alternate signature to support explicit pcb selection.

/* syscall.c */
extern int syscall(int call, ... );		//Actual syscall mechanism to initiate context
						// switch/trap into kernel
extern int syscreate(void (*fn)(), int stack);  //Syscall(REQ_CREATE) wrapper
extern int sysyield(void);			//Syscall(REQ_YIELD) wrapper
extern int sysstop(void);			//Syscall(REQ_STOP) wrapper
extern void syssleep(int ms);			//Syscall(REQ_SLEEP) wrapper

/* sleep.c */
extern void sleep(PCB* proc, int ms);	// put proc on sleep device list
extern void tick(void);				// notify sleep device of clock tick

extern unsigned int sysgetpid(void);
extern void sysputs(char* str);
extern int syssend(int dest_pid, void* buf, int len);
extern int sysrecv(unsigned int* from_pid, void* buf, int len);

/* msg.c */
extern int send(void* send_buf, int send_len, void* recv_buf, int recv_len);
extern int recv(void* send_buf, int send_len, void* recv_buf, int recv_len);


/* user.c */
extern void root(void);				//Root user process
extern void idle(void);				//Idle process
